<template>
    <div class="wrapper">
        <div id="container" ref="container"></div>
        <div class="btn-list">
            <button class="btn" @click="addNode({}, true)">add</button>
            <button class="btn" @click="format">格式化</button>
            <button class="btn" @click="save">保存</button>
        </div>
    </div>
</template>

<script>
import { Graph, Model } from "@antv/x6";
import { DagreLayout } from "@antv/layout";

export default {
    name: "",
    data () {
        return {
            graph: null,
            nodes: [],
            edges: [],
            node_width: 160,
            node_height: 32,
            edge_padding: 20, // 连线的padding
            space_x: 0, // 节点x方向最小间距
            space_y: 0, // 节点y方向最小间距
            currDir: "",
            portAttrs: {
                circle: {
                    magnet: true,
                    r: 5,
                    stroke: "#31d0c6",
                    strokeWidth: 2,
                    fill: "#fff",
                    style: {
                        visibility: "hidden"
                    }
                }
            }
        };
    },
    methods: {
        // mock一些数据
        getData () {
            this.graphData = JSON.parse(localStorage.getItem("graphData"));
            if (this.graphData) {
                this.nodes = this.graphData.nodesArr;
                this.edges = this.graphData.edgesArr;
            }
        },
        // graph初始化
        initGraph () {
            this.graph = new Graph({
                container: this.$refs.container,
                width: 1300,
                height: 800,
                grid: {
                    size: 10,
                    visible: true
                },
                panning: true,
                snapline: true,
                connecting: {
                    allowBlank: false,
                    router: {
                        name: "manhattan",
                        args: {
                            padding: 20
                        }
                    }
                }
            });
            // 初始化一些变量
            this.initVars();
            // 注册事件
            this.registEvents();
            // 新增节点
            this.nodes.forEach(item => {
                this.addNode(item);
            });
            // 新增边
            this.addEdge();
            // 更新连线
            // this.updateEdgesByCalcNodes();
            this.updateEdgesByNodePos();
        },
        // 新增节点
        addNode (item, isFromBtn) {
            this.graph.addNode({
                id: item.id || `node${this.nodes.length + 1}`,
                x: item.x || 0,
                y: item.y || 0,
                width: this.node_width,
                height: this.node_height,
                label: item.label || `节点${this.nodes.length + 1}`,
                attrs: {
                    body: {
                        fill: "#f5f5f5",
                        stroke: "#d9d9d9",
                        strokeWidth: 1
                    },
                    label: {
                        fontSize: 12
                    }
                },
                ports: {
                    groups: {
                        top: {
                            attrs: this.portAttrs,
                            zIndex: 10,
                            position: {
                                name: "top"
                            }
                        },
                        right: {
                            attrs: this.portAttrs,
                            zIndex: 10,
                            position: {
                                name: "right"
                            }
                        },
                        bottom: {
                            attrs: this.portAttrs,
                            zIndex: 10,
                            position: {
                                name: "bottom"
                            }
                        },
                        left: {
                            attrs: this.portAttrs,
                            zIndex: 10,
                            position: {
                                name: "left"
                            }
                        }
                    },
                    items: [
                        { id: "top", group: "top" },
                        { id: "right", group: "right" },
                        { id: "bottom", group: "bottom" },
                        { id: "left", group: "left" }
                    ]
                }
            });
            isFromBtn && this.nodes.push(item);
        },
        // 新增边
        addEdge () {
            this.edges.forEach(edge => {
                this.graph.addEdge({
                    source: edge.source,
                    target: edge.target,
                    vertices: edge.vertices || {},
                    router: {
                        name: "manhattan",
                        args: {
                            padding: this.edge_padding
                        }
                    },
                    connector: {
                    },
                    zIndex: 1
                });
            });
        },
        // Dagre布局
        setDagreLayout () {
            const config = {};
            if (this.currDir === "LR") {
                config.ranksep = 70;
                config.nodesep = 15;
            } else if (this.currDir === "TB") {
                config.ranksep = 20;
                config.nodesep = 60;
            }
            const dagreLayout = new DagreLayout({
                type: "dagre",
                rankdir: this.currDir,
                ranksep: config.ranksep,
                // align: "UL",
                nodesep: config.nodesep
            });
            const nodesArr = this.graph.getNodes();
            const nodes = nodesArr.map(node => ({ id: node.id, label: node.label }));
            const edges = this.graph.getEdges();
            // Dagre布局
            const model = dagreLayout.layout({ nodes, edges });
            // 各节点调整位置
            nodesArr.forEach(node => {
                const dagreNode = model.nodes.find(val => val.id === node.id);
                if (dagreNode) {
                    node.position(dagreNode.x, dagreNode.y);
                }
            });
            // 更新连线
            // this.updateEdges();
            // 更新连线 - 指定连接桩
            // this.updateEdgesByports();
            // 更新连线 - 通过计算source和target位置
            this.updateEdgesByNodePos();
        },
        // 更新连线
        updateEdges () {
            this.graph.getEdges().forEach(edge => {
                // 获取连线起始node
                const sourceNode = this.graph.getCellById(edge.source.cell);
                const targetNode = this.graph.getCellById(edge.target.cell);
                // 获取起止元素中心点坐标
                const nodeSourceX = sourceNode.position().x + this.node_width / 2;
                const nodeSourceY = sourceNode.position().y + this.node_height / 2;
                const nodeTargetX = targetNode.position().x + this.node_width / 2;
                const nodeTargetY = targetNode.position().y + this.node_height / 2;
                /**
                 * 设置拐点
                 */
                // LR布局
                let p1 = {};
                let p2 = {};
                if (this.currDir === "LR") {
                    p1 = { x: (nodeSourceX + nodeTargetX) / 2, y: nodeSourceY };
                    p2 = { x: (nodeSourceX + nodeTargetX) / 2, y: nodeTargetY };
                    edge.setVertices([p1, p2]);
                // TB布局
                } else if (this.currDir === "TB") {
                    p1 = { x: nodeSourceX, y: (nodeSourceY + nodeTargetY) / 2 };
                    p2 = { x: nodeTargetX, y: (nodeSourceY + nodeTargetY) / 2 };
                    edge.setVertices([p1, p2]);
                }
                edge.setRouter({
                    name: "orth"
                });

                console.log(edge.getPolyline());
            });
        },
        // 更新连线 - 指定连接桩
        updateEdgesByports () {
            this.graph.getEdges().forEach(edge => {
                // debugger;
                edge.setRouter({
                    name: "manhattan",
                    args: {
                        step: 10,
                        // padding: this.edge_padding,
                        padding: 20
                        // startDirections: this.currDir === "LR" ? ["left", "right"] : ["top", "bottom"],
                        // endDirections: this.currDir === "LR" ? ["left", "right"] : ["top", "bottom"]
                    }
                });
            });
        },
        // 更新连线 - 通过计算source和target位置
        updateEdgesByNodePos () {
            this.graph.getNodes().forEach(node => {
                // console.log(`${node.id}:`);
                // console.log("前序节点:");
                // console.log(this.graph.getPredecessors(node));
                // console.log("邻居节点:");
                // console.log(this.graph.getNeighbors(node));
                // 获取当前节点的输出连线
                // const outgoingEdges = this.graph.getOutgoingEdges(node);

                // 如果有多条输出线
                // if (outgoingEdges.length > 1) {
                //     const xDirNodes = [];
                //     const yDirNodes = [];
                //     outgoingEdges.forEach(edge => {

                //     });

                // }

                // 获取当前节点的输出连线
                // const targetEdges = this.graph.getOutgoingEdges(node);
                // if (targetEdges) {
                //     // 如果有多条
                //     if (targetEdges.length > 1) {
                //         const sameDirNodes = [];
                //         // 判断是否都在下面
                //         targetEdges.forEach(t => {
                //             if (t.getTargetCell().position().y > node.position().y) {
                //                 sameDirNodes.push(t.getTargetCell());
                //             }
                //         });
                //         if (sameDirNodes.length === targetEdges.length) {
                //             targetEdges.forEach(t => {
                //                 t.setRouter({
                //                     name: "manhattan",
                //                     args: {
                //                         padding: this.edge_padding,
                //                         startDirections: "bottom",
                //                         endDirections: "top"
                //                     }
                //                 });
                //             });
                //         }
                //     }
                // }
            });
        },
        // 更新连线
        updateEdgesByCalcNodes () {
            this.graph.getNodes().forEach(node => {
                node.clearVertices();
                // 获取当前节点的输出线
                const targetEdges = this.graph.getOutgoingEdges(node);
                if (targetEdges) {
                    // 如果只有一条输出线
                    if (targetEdges.length === 1) {
                        const targetNode = targetEdges[0].getTargetCell();
                        const sourceNodePos = this.alterNodeConter(node);
                        const targetNodePos = this.alterNodeConter(targetNode);
                        if (targetNodePos.x > sourceNodePos.x) {
                            const p1 = {
                                x: targetNodePos.x - 20 - this.node_width / 2,
                                y: targetNodePos.y
                            };
                            const p2 = {
                                x: targetNodePos.x - 20 - this.node_width / 2,
                                y: targetNodePos.y
                            };
                            targetEdges[0].setVertices([p1, p2]);
                        }
                    }
                }
            });
        },
        // 保存
        save () {
            const nodesArr = [];
            const nodes = this.graph.getNodes();
            nodes.forEach(node => {
                nodesArr.push({
                    id: node.id,
                    label: node.label,
                    ...node.position()
                });
            });

            const edgesArr = [];
            const edges = this.graph.getEdges();
            edges.forEach(edge => {
                edgesArr.push({
                    source: edge.getSource().cell,
                    target: edge.getTarget().cell
                });
            });
            const graphData = { nodesArr, edgesArr };
            localStorage.setItem("graphData", JSON.stringify(graphData));
        },
        // 初始化一些变量
        initVars () {
            this.space_x = this.node_width + this.edge_padding * 2 + this.graph.options.grid.size;
            this.space_y = this.node_height + this.edge_padding * 2 + this.graph.options.grid.size;
        },
        // 注册一些事件
        registEvents () {
            // 显示/隐藏事件
            const showPorts = (ports, show) => {
                for (let i = 0, len = ports.length; i < len; i++) {
                    ports[i].style.visibility = show ? "visible" : "hidden";
                }
            };
            // 鼠标移入，显示连接桩
            this.graph.on("node:mouseenter", () => {
                const ports = this.$refs.container.querySelectorAll(".x6-port-body");
                showPorts(ports, true);
            });
            // 鼠标移出，隐藏连接桩
            this.graph.on("node:mouseleave", () => {
                const ports = this.$refs.container.querySelectorAll(".x6-port-body");
                showPorts(ports, false);
            });

            // 节点移动
            this.graph.on("node:moving", ({ e, x, y, node }) => {
                // const connectedEdges = this.graph.getConnectedEdges(node);
                // connectedEdges.forEach(edge => {
                //     const sourceNode = edge.getSourceCell();
                //     const targetNode = edge.getTargetCell();
                //     const sourcePos = this.alterNodeConter(sourceNode);
                //     const targetPos = this.alterNodeConter(targetNode);
                //     const dx = targetPos.x - sourcePos.x; // target - source x
                //     const dy = targetPos.y - sourcePos.y; // target - source y
                //     console.log(dx);

                //     // 如果target在source右边，且两节点dx > space_x，source右出，target左进
                //     if (targetPos.x > sourcePos.x && targetPos.x - sourcePos.x > this.space_x) {
                //         edge.setSource({ cell: sourceNode.id, port: "right" });
                //         edge.setTarget({ cell: targetNode.id, port: "left" });
                //     // 如果target在source右边，且两节点dx < space_x,target在source上面，source上出，target上进
                //     } else if (targetPos.x > sourcePos.x && targetPos.x - sourcePos.x <= this.space_x && targetPos.y - sourcePos.y <= 0) {
                //         edge.setSource({ cell: sourceNode.id, port: "top" });
                //         edge.setTarget({ cell: targetNode.id, port: "top" });
                //     // 如果target在source右边，且两节点 0 < dx < space_x，且 |dy| < space_y，source右出，target右进
                //     } else if (targetPos.x > sourcePos.x && dx >= 0 && dx < this.space_x && Math.abs(dy) <= this.space_y) {
                //         edge.setSource({ cell: sourceNode.id, port: "right" });
                //         edge.setTarget({ cell: targetNode.id, port: "right" });
                //     // 如果target在source左边，且两节点dx > space_x,source左出，target右进
                //     } else if (targetPos.x < sourcePos.x && sourcePos.x - targetPos.x > this.space_x) {
                //         edge.setSource({ cell: sourceNode.id, port: "left" });
                //         edge.setTarget({ cell: targetNode.id, port: "right" });
                //     // 如果target在source左边，且两节点 0 > dx > space_x，且 |dy| < space_y，source左出，target左进
                //     } else if (targetPos.x < sourcePos.x && dx < 0 && dx > -this.space_x && Math.abs(dy) <= this.space_y) {
                //         edge.setSource({ cell: sourceNode.id, port: "left" });
                //         edge.setTarget({ cell: targetNode.id, port: "left" });
                //     // 如果target在source上面，且两节点 dx < space_x,source上出，target下进
                //     } else if (targetPos.y < sourcePos.y && sourcePos.x - targetPos.x < this.space_x) {
                //         edge.setSource({ cell: sourceNode.id, port: "top" });
                //         edge.setTarget({ cell: targetNode.id, port: "bottom" });
                //     // 如果target在source下面，且两节点 dx < space_x,source下出，target上进
                //     } else if (targetPos.y > sourcePos.y && sourcePos.x - targetPos.x < this.space_x) {
                //         edge.setSource({ cell: sourceNode.id, port: "bottom" });
                //         edge.setTarget({ cell: targetNode.id, port: "top" });
                //     }
                // });
            });

            this.graph.on("edge:connected", ({ isNew, edge }) => {
                edge.setSource(edge.getSourceCell());
                edge.setTarget(edge.getTargetCell());
            });
        },
        // 转换节点position为中心点
        alterNodeConter (node) {
            return {
                x: node.position().x + this.node_width / 2,
                y: node.position().y + this.node_height / 2
            };
        },
        // 格式化
        format () {
            this.currDir = this.currDir === "LR" ? "TB" : "LR";
            this.setDagreLayout();
        }
    },
    created () {},
    mounted () {
        this.getData();
        this.initGraph();
    }
};
</script>

<style scoped>
.wrapper {
    display: flex;
}
.btn-list {
    margin: 0 0 0 10px;
}
.btn {
    display: block;
    width: 50px;
    height: 20px;
    margin: 0 0 10px 0;
}
</style>
